package com.wedistudio.android.framework.service;

import java.util.List;
import java.util.Map;

import com.wedistudio.android.framework.fetcher.DefaultFetcher;
import com.wedistudio.android.framework.fetcher.URLParams;

import android.os.AsyncTask;

public abstract class Service<I extends ServiceRequest, O extends ServiceResponse> {
	private ServiceRequestConverter<I> requestConverter;
	private ServiceResponseConverter<O> responseConverter;
	private ServiceFetcher fetcher;

	public void setRequestConverter(ServiceRequestConverter<I> requestConverter) {
		this.requestConverter = requestConverter;
	}

	public void setResponseConverter(ServiceResponseConverter<O> outputConverter) {
		this.responseConverter = outputConverter;
	}

	public void setFetcher(ServiceFetcher fetcher) {
		this.fetcher = fetcher;
	}

	private static ServiceFetcher DEFAULT_FETCHER;

	private O exec(I request) throws ServiceException {
		if (requestConverter == null)
			throw new ServiceException("requestConverter is not defined");

		if (responseConverter == null)
			throw new ServiceException("responseConverter is not defined");

		if (fetcher == null) {
			if(DEFAULT_FETCHER == null)
				DEFAULT_FETCHER = new DefaultFetcher();
			
			fetcher = DEFAULT_FETCHER;
		}

		List<URLParams> urls = requestConverter.convert(request);
		Map<URLParams, String> raw = fetcher.fetch(urls);
		return responseConverter.convert(raw);
	}

	private class BackgroundTask extends AsyncTask<I, Void, Void> {

		private Service<I, O> service;
		private ServiceOnSuccess<O> success;
		private ServiceOnFailure fail;

		public BackgroundTask(Service<I, O> service, ServiceOnSuccess<O> success, ServiceOnFailure fail) {
			super();
			this.service = service;
			this.success = success;
			this.fail = fail;
		}

		@Override
		protected Void doInBackground(I... params) {
			try {
				O response = service.exec(params[0]);
				success.take(response);
			} catch (ServiceException e) {
				fail.take(e);
			}

			return null;
		}

	}

	@SuppressWarnings("unchecked")
	public void execAsync(I request, ServiceOnSuccess<O> success, ServiceOnFailure fail) {
		BackgroundTask task = new BackgroundTask(this, success, fail);
		task.execute(request);
	}
}
